// $Id: html.c 495 2014-05-07 00:15:06Z alan.watson.f $

#define _POSIX_C_SOURCE 200112L

#include <errno.h>
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

#include <sys/statfs.h>

#include "oaxaca-config.h"
#include "oaxaca.h"

#include "mprintf.h"

////////////////////////////////////////////////////////////////////////////////

static const char *wwwdir = "../../www";

static FILE *
start(char *name)
{
  char *newfullname = mprintf("%s/%s.new", wwwdir, name);
  FILE *fp = fopen(newfullname, "w");
  free(newfullname);
  if (fp == NULL)
    oaxaca_error("fopen() failed.");
  return fp;
}

static void
end(char *name, FILE *fp)
{
  fclose(fp);
  char *newfullname = mprintf("%s/%s.new", wwwdir, name);
  char *fullname = mprintf("%s/%s", wwwdir, name);
  if (rename(newfullname, fullname) != 0)
    oaxaca_error("rename() failed.");
}

////////////////////////////////////////////////////////////////////////////////

static void
format_double_with_sign(FILE *fp, const char *format, double x)
{
  if (x < 0.0)
    fprintf(fp, "&minus;");
  else
    fprintf(fp, "+");
  fprintf(fp, format, fabs(x));
}

static void
detector_summary(FILE *fp, int index)
{
  volatile oaxaca_detector_t *detector = &oaxaca_shm->detector[index];
  
  fprintf(fp, "<tr><td>Frame frequency</td><td>%.2f Hz</td></tr>\n", 
    detector->framefrequency);
  fprintf(fp, "<tr><td>Integration/Exposure Time</td><td>%.3f %.3f</td></tr>\n", 
    detector->integrationtime, detector->exposuretime);
  fprintf(fp, "<tr><td>Frame/Integration</td><td>%lu of %lu %lu of %lu</td></tr>\n", 
    (detector->framesperintegration == 0) ? 0 : detector->frame % detector->framesperintegration, 
    detector->framesperintegration,
    detector->integration, detector->integrationsperexposure);  
  fprintf(fp, "<tr><td>Min/Mean/Max</td><td>");
  format_double_with_sign(fp, "%.0f", detector->zmin);
  fprintf(fp, " ");
  format_double_with_sign(fp, "%.0f", detector->zmean);
  fprintf(fp, " ");
  format_double_with_sign(fp, "%.0f", detector->zmax);
  fprintf(fp, "</td></tr>\n");
  fprintf(fp, "<tr><td>FWHM/ESHM</td><td>%.2f pixel %.2f arcsec %.0f</td></tr>\n", 
    detector->fwhm, detector->fwhm * detector->scale, detector->eshm);
}

static void
update_wfs_summary(void)
{
  FILE *fp = start("wfs-summary.html");
  fprintf(fp, "<table>\n");
  fprintf(fp, "<tr><td>Command</td><td>%c</td></tr>\n", oaxaca_shm->wfs.command);
  detector_summary(fp, OAXACA_DETECTOR_INDEX_WFS);
  fprintf(fp, "</table>\n");
  end("wfs-summary.html", fp);
}

static void
update_instrument_summary(void)
{
  FILE *fp = start("instrument-summary.html");
  fprintf(fp, "<table>\n");
  fprintf(fp, "<tr><td>Command</td><td>%c</td></tr>\n", oaxaca_shm->instrument.command);
  detector_summary(fp, OAXACA_DETECTOR_INDEX_INSTRUMENT);
  fprintf(fp, "</table>\n");
  end("instrument-summary.html", fp);
}

static void
update_finder_summary(void)
{
  FILE *fp = start("finder-summary.html");
  fprintf(fp, "<table>\n");
  fprintf(fp, "<tr><td>Command</td><td>%c</td></tr>\n", oaxaca_shm->finder.command);
  detector_summary(fp, OAXACA_DETECTOR_INDEX_FINDER);
  fprintf(fp, "</table>\n");
  end("finder-summary.html", fp);
}

////////////////////////////////////////////////////////////////////////////////

static void
update_wfc_summary(void)
{
  FILE *fp = start("wfc-summary.html");
  fprintf(fp, "<table>\n");
  fprintf(fp, "<tr><td>Command</td><td>%c</td></tr>\n", oaxaca_shm->wfc.command);
  for (int i = 0; i < OAXACA_NA_MAX; ++i) {
    fprintf(fp, "<tr><td>Mode %d</td><td>", i);
    double a = oaxaca_shm->wfc.amean[i];
    if (a == -1.0 || a == +1.0) {
      fprintf(fp, "<emph class=\"saturated\">");
      format_double_with_sign(fp, "%.3f", a);
      fprintf(fp, "</emph>");
    } else {
      format_double_with_sign(fp, "%.3f", a);
    }
    fprintf(fp, " ± %.3f ", oaxaca_shm->wfc.asigma[i]);
    format_double_with_sign(fp, "%.3f", oaxaca_shm->wfc.damean[i]);
    fprintf(fp, " ± %.3f", oaxaca_shm->wfc.dasigma[i]);
    fprintf(fp, " %.2f\n", oaxaca_shm->wfc.asaturated[i]);
    if (i == 0) {
      if (a > +0.2)
        fprintf(fp, " E");
      else if (a < -0.2)
        fprintf(fp, " W");
    } else if (i == 1) {
      if (a > +0.2)
        fprintf(fp, " S");
      else if (a < -0.2)
        fprintf(fp, " N");
    } else if (i == 2) {
      if (a > +0.2)
        fprintf(fp, " U");
      else if (a < -0.2)
        fprintf(fp, " D");
    }
    fprintf(fp, "</td></tr>\n");
  }
  fprintf(fp, "<tr><td>TM Voltages (0-2)</td><td>%.2f %.2f %.2f</td></tr>\n", 
    oaxaca_shm->wfc.tmv[0], oaxaca_shm->wfc.tmv[1], oaxaca_shm->wfc.tmv[2]);
  for (int i = 0; i < 64; ++i) {
    if (i % 8 == 0)
      fprintf(fp, "<tr><td>DM Voltages (%d-%d)</td><td>", i, i + 7);
    else
      fprintf(fp, " ");
    double v = oaxaca_shm->wfc.dmv[i];
    if (v == +1.0)
      fprintf(fp, "<emph class=\"saturated\">%.2f</emph>", v);
    else
      fprintf(fp, "%.2f", v);
    if (i % 8 == 7)
      fprintf(fp, "</td></tr>\n");
  }
  fprintf(fp, "</table>\n");
  end("wfc-summary.html", fp);
}

////////////////////////////////////////////////////////////////////////////////

static void
update_lamp_summary(void)
{
  FILE *fp = start("lamp-summary.html");
  fprintf(fp, "<table>\n");
  fprintf(fp, "<tr><td>Command</td><td>%c</td></tr>\n", oaxaca_shm->lamp.command);
  fprintf(fp, "<tr><td>State</td><td>%s</td></tr>\n", oaxaca_shm->lamp.state ? "On" : "Off");
  fprintf(fp, "</table>\n");
  end("lamp-summary.html", fp);
}

////////////////////////////////////////////////////////////////////////////////

static void
update_dimm_summary(void)
{
  FILE *fp = start("dimm-summary.html");
  fprintf(fp, "<table>\n");
  fprintf(fp, "<tr><td>r0</td><td>%.1f cm</td></tr>\n", oaxaca_shm->dimm.r0 * 100);
  fprintf(fp, "<tr><td>λ</td><td>%.0f nm</td></tr>\n", oaxaca_shm->dimm.lambda * 1e9);
  fprintf(fp, "<tr><td>FWHM</td><td>%.2f arcsec</td></tr>\n", oaxaca_shm->dimm.fwhm);
  fprintf(fp, "</table>\n");
  end("dimm-summary.html", fp);
}

////////////////////////////////////////////////////////////////////////////////

static void
update_housekeeping_summary(void)
{
  FILE *fp = start("housekeeping-summary.html");
  fprintf(fp, "<table>\n");
  fprintf(fp, "<tr><td>Finder?</td><td>%s</td></tr>\n", oaxaca_shm->finder.initialized ? "OK" : "<emph class=\"warning\">Unknown</emph>");
  fprintf(fp, "<tr><td>Housekeeping?</td><td>%s</td></tr>\n", oaxaca_shm->housekeeping.initialized ? "OK" : "<emph class=\"warning\">Unknown</emph>");
  fprintf(fp, "<tr><td>Instrument?</td><td>%s</td></tr>\n", oaxaca_shm->instrument.initialized ? "OK" : "<emph class=\"warning\">Unknown</emph>");
  fprintf(fp, "<tr><td>CPU Usage</td><td>%.0f%%</td></tr>\n", oaxaca_shm->housekeeping.cpu_usage * 100);
  fprintf(fp, "<tr><td>Disk Usage</td><td>%.0f%%</td></tr>\n", oaxaca_shm->housekeeping.disk_usage * 100);
  fprintf(fp, "</table>\n");
  end("housekeeping-summary.html", fp);
}

////////////////////////////////////////////////////////////////////////////////

static void
update_telescope_summary(void)
{
  FILE *fp = start("telescope-summary.html");
  fprintf(fp, "<table>\n");
  fprintf(fp, "<tr><td>⍺ δ</td><td>%.4f %+.4f</td></tr>\n", oaxaca_shm->telescope.alpha, oaxaca_shm->telescope.delta);
  fprintf(fp, "<tr><td>HA ZD</td><td>%+.1f % .1f</td></tr>\n", oaxaca_shm->telescope.ha, oaxaca_shm->telescope.zd);
  fprintf(fp, "</table>\n");
  end("telescope-summary.html", fp);
}

////////////////////////////////////////////////////////////////////////////////

static void
update(void)
{
  update_wfs_summary();
  update_instrument_summary();
  update_finder_summary();
  update_wfc_summary();
  update_dimm_summary();
  update_lamp_summary();
  update_housekeeping_summary();
  update_telescope_summary();
}

////////////////////////////////////////////////////////////////////////////////

void
oaxaca_html_main(void)
{
  int interval = 1;

  oaxaca_common_main("html");
  
  oaxaca_info("starting loop.");
  for (;;) {
    oaxaca_sleep(interval);
    update();
  }
  
  oaxaca_error("loop terminated.");
}

////////////////////////////////////////////////////////////////////////////////